package database

import (
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"sync"

	configrations "gitee.com/chenjihao00/common-service/configrations/sqlite"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type Sqlite struct {
	config *configrations.SqliteConfigration
	db     *gorm.DB
	once   sync.Once
	err    error
}

func NewSqlite(fileName string, opts ...configrations.SqliteConfigrationOption) *Sqlite {
	config := configrations.NewSqliteConfigation(fileName, opts...)
	return &Sqlite{
		config: config,
	}
}

func (s *Sqlite) Config() *configrations.SqliteConfigration {
	return s.config
}

func (s *Sqlite) connectToDB() (*gorm.DB, error) {
	var dsn string

	if s.config.FileName == ":memory:" {
		dsn = ":memory:"
	} else {
		absPath, err := filepath.Abs(s.config.FileName)
		if err != nil {
			return nil, fmt.Errorf("failed to resolve db path '%s': %w", s.config.FileName, err)
		}
		// 使用 PRAGMA 提升稳定性和性能
		params := []string{
			"_pragma=journal_mode(WAL)",
			"_pragma=busy_timeout(5000)",
			"_pragma=cache_size(10000)",
		}
		dsn = fmt.Sprintf("%s?%s", absPath, strings.Join(params, "&"))
	}

	var logLevel logger.LogLevel
	switch strings.ToLower(s.config.LogLevel) {
	case "silent":
		logLevel = logger.Silent
	case "error":
		logLevel = logger.Error
	case "warn":
		logLevel = logger.Warn
	default:
		logLevel = logger.Info
	}

	gormConfig := &gorm.Config{
		Logger: logger.Default.LogMode(logLevel),
	}

	db, err := gorm.Open(sqlite.Open(dsn), gormConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to open gorm db: %w", err)
	}

	// 设置连接池（SQLite 写入建议单连接）
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("failed to get raw db: %w", err)
	}

	maxOpen := s.config.MaxOpenConns
	if maxOpen == 0 {
		maxOpen = 1 // 默认单连接写入
	}
	maxIdle := s.config.MaxIdleConns
	if maxIdle == 0 {
		maxIdle = 1
	}
	sqlDB.SetMaxOpenConns(maxOpen)
	sqlDB.SetMaxIdleConns(maxIdle)
	sqlDB.SetConnMaxLifetime(s.config.ConnMaxLifetime) // 永不关闭

	return db, nil
}
func (s *Sqlite) DB() (*gorm.DB, error) {
	s.once.Do(func() {
		db, err := s.connectToDB()
		if err != nil {
			s.err = fmt.Errorf("failed to connect to sqlite database: %w", err)
			return
		}
		s.db = db
		log.Printf("Connected to SQLite database: %s", s.config.FileName)
	})
	return s.db, s.err
}

func (s *Sqlite) Close() error {
	if s.db != nil {
		sqlDB, err := s.db.DB()
		if err != nil {
			return err
		}
		if err := sqlDB.Close(); err != nil {
			return fmt.Errorf("failed to close sqlite database: %w", err)
		}
		log.Printf("SQLite database closed: %s", s.config.FileName)
	}
	return nil
}

func (s *Sqlite) Migrate(models ...interface{}) error {
	db, err := s.DB()
	if err != nil {
		return fmt.Errorf("failed to get database instance for migration: %w", err)
	}
	log.Printf("Running AutoMigrate for %d models", len(models))
	if err := db.AutoMigrate(models...); err != nil {
		return fmt.Errorf("auto migrate failed: %w", err)
	}
	return nil
}
